home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 17 / CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso / CUCD / Programming / DiceSource / src / dutil / dprof.c < prev    next >
C/C++ Source or Header  |  1997-09-09  |  11KB  |  472 lines

  1. /*
  2.  *    (c)Copyright 1992-1997 Obvious Implementations Corp.  Redistribution and
  3.  *    use is allowed under the terms of the DICE-LICENSE FILE,
  4.  *    DICE-LICENSE.TXT.
  5.  */
  6.  
  7. /*
  8.  *  DPROF.C
  9.  *
  10.  *  DPROF <dproffile> [-call]
  11.  */
  12.  
  13. #include <stdio.h>
  14. #include <string.h>
  15. #include <stdlib.h>
  16. #include <fcntl.h>
  17.  
  18. #ifdef AMIGA
  19. #include <lib/profile.h>
  20. #include <lib/version.h>
  21. #include <lib/muldiv.h>
  22. #else
  23. #include <include/lib/profile.h>
  24. #include <include/lib/version.h>
  25. #include <include/lib/muldiv.h>
  26. #endif
  27.  
  28. ProfSym **ProfAry;
  29. ProfSym *ProfList;
  30. ProfSym *ProfData;
  31.  
  32. void DumpProfInfo(void);
  33. void DumpProfInfoFrom(ProfSym *);
  34. void DumpProfTree(long, ProfSym *, short, long);
  35. void DumpCombineProfTree(ProfSym *);
  36. void SortProfList(void);
  37. void help(int);
  38. char *NameOf(ProfSym *);
  39. short NoLoop(ProfSym *, ProfSym *);
  40.  
  41. unsigned long TimeBase;
  42. short MaxSymLen;
  43. short CallTreeOpt;
  44. char    FileName[256];
  45.  
  46. IDENT("dprof", ".1");
  47. DCOPYRIGHT;
  48.  
  49. main(ac, av)
  50. char *av[];
  51. {
  52.     int fd;
  53.     short i;
  54.     ProfHdr phdr;
  55.  
  56.     for (i = 1; i < ac; ++i) {
  57.     char *ptr = av[i];
  58.     if (*ptr != '-') {
  59.         strcpy(FileName, ptr);
  60.         continue;
  61.     }
  62.     ptr += 2;
  63.     switch(ptr[-1]) {
  64.     case 'c':
  65.         CallTreeOpt = 1;
  66.         break;
  67.     default:
  68.         help(0);
  69.     }
  70.     }
  71.     if (FileName[0] == 0)
  72.     help(0);
  73.  
  74.     strcat(FileName, ".dprof");
  75.     if ((fd = open(FileName, O_RDONLY|O_BINARY)) < 0) {
  76.     FileName[strlen(FileName) - 6] = 0;
  77.     if ((fd = open(FileName, O_RDONLY|O_BINARY)) < 0) {
  78.         printf("Unable to open %s\n", FileName);
  79.         exit(10);
  80.     }
  81.     }
  82.     if (read(fd, &phdr, sizeof(phdr)) != sizeof(phdr) || phdr.ph_Magic != PROF_MAGIC) {
  83.     printf("%s not a dprof file\n", FileName);
  84.     exit(20);
  85.     }
  86.     if ((ProfAry = malloc(phdr.ph_NumIds * sizeof(ProfSym *))) == NULL) {
  87.     puts("no memory");
  88.     exit(20);
  89.     }
  90.     TimeBase = phdr.ph_TimeBase;
  91.     clrmem(ProfAry, phdr.ph_NumIds * sizeof(ProfSym *));
  92.     {
  93.     long n;
  94.     ProfSym *ps;
  95.  
  96.     n = lseek(fd, 0L, 2);
  97.  
  98.     if ((ProfData = malloc(n)) == NULL) {
  99.         puts("no memory!");
  100.         exit(20);
  101.     }
  102.     lseek(fd, 0L, 0);
  103.     if (read(fd, ProfData, n) != n) {
  104.         printf("read error\n");
  105.         exit(20);
  106.     }
  107.     for (ps = (ProfSym *)((ProfHdr *)ProfData + 1); (char *)ps < ((char *)ProfData + n); ps = (ProfSym *)((char *)ps + ps->ps_Size)) {
  108.         long i = ps->ps_Id;
  109.  
  110.         ps->ps_TimeStamp = 0;
  111.         ps->ps_AccumTime = 0;
  112.  
  113.         if (i < 0 || i >= phdr.ph_NumIds) {
  114.         printf("illegal id: %d\n", i);
  115.         exit(20);
  116.         }
  117.         ProfAry[i] = ps;
  118.         if (ps->ps_FuncName[0]) {
  119.         short len;
  120.  
  121.         ps->ps_Link = ProfList;
  122.         ProfList = ps;
  123.  
  124.         if ((len = strlen(ps->ps_FuncName)) > MaxSymLen)
  125.             MaxSymLen = len;
  126.         } else if (ProfList) {
  127.         ps->ps_SibLink = ProfList->ps_SibLink;
  128.         ProfList->ps_SibLink = ps;
  129.         }
  130.     }
  131.     for (ps = (ProfSym *)((ProfHdr *)ProfData + 1); (char *)ps < ((char *)ProfData + n); ps = (ProfSym *)((char *)ps + ps->ps_Size)) {
  132.         if (ps->ps_Parent)
  133.         ps->ps_Parent = ProfAry[(long)ps->ps_Parent];
  134.     }
  135.     }
  136.  
  137.     printf("\n%s\t\t%s\n\n", Ident, FileName);
  138.  
  139.     DumpProfInfo();
  140.     return(0);
  141. }
  142.  
  143. void
  144. help(code)
  145. {
  146.     printf("%s\n%s\n", Ident, DCopyright);
  147.     exit(code);
  148. }
  149.  
  150. void
  151. DumpProfInfo()
  152. {
  153.     ProfSym *ps;
  154.     unsigned long grandTotal = 0;
  155.  
  156.     /*
  157.      *    Id for quick name reference
  158.      */
  159.  
  160.     for (ps = ProfList; ps; ps = ps->ps_Link) {
  161.     ProfSym *ps2;
  162.     for (ps2 = ps; ps2; ps2 = ps2->ps_SibLink)
  163.         ps2->ps_Id = ps->ps_Id;
  164.     }
  165.  
  166.     /*
  167.      *    AccumTime   total time used by node & subroutines for all instances
  168.      *            (only good in header node of proflist)
  169.      *
  170.      *    TotalTime   total time used by node & subroutines
  171.      *
  172.      *    TimeStamp   local time used by this node only
  173.      */
  174.  
  175.  
  176.     for (ps = ProfList; ps; ps = ps->ps_Link) {
  177.     ProfSym *ps2;
  178.     long total = 0;
  179.     long calls = 0;
  180.  
  181.     if (ps->ps_Parent == NULL)
  182.         grandTotal += ps->ps_TotalTime;
  183.  
  184.     for (ps2 = ps; ps2; ps2 = ps2->ps_SibLink) {
  185.         if (NoLoop(ps, ps2))
  186.         total += ps2->ps_TotalTime;
  187.  
  188.         if (ps2->ps_Parent)
  189.         ps2->ps_Parent->ps_TimeStamp += ps2->ps_TotalTime;
  190.     }
  191.     ps->ps_AccumTime = total;
  192.     }
  193.  
  194.     for (ps = ProfList; ps; ps = ps->ps_Link) {
  195.     ProfSym *ps2;
  196.  
  197.     for (ps2 = ps; ps2; ps2 = ps2->ps_SibLink)
  198.         ps2->ps_TimeStamp = ps2->ps_TotalTime - ps2->ps_TimeStamp;
  199.     }
  200.  
  201.     printf("GrandTotal: %5ld.%02d mS\n",
  202.     MulDivU(grandTotal, 1000, TimeBase), MulDivU(grandTotal, 100000, TimeBase) % 100,
  203.     );
  204.     printf("\n**** BY ROUTINE ****\n\n");
  205.  
  206.     /*
  207.      *    sort by total time
  208.      */
  209.  
  210.     SortProfList();
  211.  
  212.     /*
  213.      *    display master statistics
  214.      */
  215.  
  216.     for (ps = ProfList; ps; ps = ps->ps_Link) {
  217.     ProfSym *ps2;
  218.     long total = 0;
  219.     long local = 0;
  220.     long calls = 0;
  221.  
  222.     for (ps2 = ps; ps2; ps2 = ps2->ps_SibLink) {
  223.         if (NoLoop(ps, ps2))
  224.         total += ps2->ps_TotalTime;
  225.         local += ps2->ps_TimeStamp;
  226.         calls += ps2->ps_NumCalls;
  227.     }
  228.     printf("%-*s calls=%-6d ", MaxSymLen, ps->ps_FuncName, calls);
  229.     printf("total=%5ld.%02d mS (%3d.%02d%%) local=%5ld.%02d mS (%3d.%02d%%)\n",
  230.         MulDivU(total, 1000, TimeBase), MulDivU(total, 100000, TimeBase) % 100,
  231.         MulDivU(total, 100, grandTotal), MulDivU(total, 10000, grandTotal) % 100,
  232.  
  233.         MulDivU(local, 1000, TimeBase), MulDivU(local, 100000, TimeBase) % 100,
  234.         MulDivU(local, 100, grandTotal), MulDivU(local, 10000, grandTotal) % 100
  235.     );
  236.     }
  237.  
  238.     printf("\n**** BY PARENT ****\n\n");
  239.  
  240.     for (ps = ProfList; ps; ps = ps->ps_Link) {
  241.     if (ps->ps_SibLink)
  242.         DumpProfInfoFrom(ps);
  243.     }
  244.  
  245.     printf("\n**** COMBINED CALL TREE ****\n\n");
  246.  
  247.     for (ps = ProfList; ps; ps = ps->ps_Link)
  248.     DumpCombineProfTree(ps);
  249.  
  250.     if (CallTreeOpt) {
  251.     printf("\n**** CALL TREE ****\n\n");
  252.  
  253.     for (ps = ProfList; ps; ps = ps->ps_Link) {
  254.         if (ps->ps_Parent == NULL)
  255.         DumpProfTree(ps->ps_TotalTime, ps, 0, 32768);
  256.     }
  257.     }
  258. }
  259.  
  260. void
  261. DumpProfInfoFrom(ps)
  262. ProfSym *ps;
  263. {
  264.     ProfSym *ps2;
  265.     long total = 0;
  266.     long calls = 0;
  267.  
  268.     for (ps2 = ps; ps2; ps2 = ps2->ps_SibLink) {
  269.     if (NoLoop(ps, ps2))
  270.         total += ps2->ps_TotalTime;
  271.     calls += ps2->ps_NumCalls;
  272.     }
  273.     printf("%-*s calls=%-6d ", MaxSymLen, ps->ps_FuncName, calls);
  274.     printf("total=%5ld.%02d mS\n",
  275.     MulDivU(total, 1000, TimeBase), MulDivU(total, 100000, TimeBase) % 100
  276.     );
  277.     for (ps2 = ps; ps2; ps2 = ps2->ps_SibLink) {
  278.     printf("    From %-*s calls=%-6d ", MaxSymLen, NameOf(ps2->ps_Parent), ps2->ps_NumCalls);
  279.     printf("total=%5ld.%02d mS (%3d.%02d%%)\n",
  280.         MulDivU(ps2->ps_TotalTime, 1000, TimeBase), MulDivU(ps2->ps_TotalTime, 100000, TimeBase) % 100,
  281.         MulDivU(ps2->ps_TotalTime, 100, total), MulDivU(ps2->ps_TotalTime, 10000, total) % 100
  282.     );
  283.     }
  284. }
  285.  
  286. void
  287. DumpProfTree(total, ps, tab, limit)
  288. long total;
  289. ProfSym *ps;
  290. short tab;
  291. long limit;
  292. {
  293.     ProfSym *ps1;
  294.     ProfSym *ps2;
  295.     short cnt = 0;
  296.  
  297.     printf("%*.*s%-*s calls=%-5ld tot=%5ld.%02d (%3d.%02d)  loc=%5ld.%02d (%3d.%02d)",
  298.     tab, tab, "",
  299.     MaxSymLen, NameOf(ps),
  300.     ps->ps_NumCalls,
  301.     MulDivU(ps->ps_TotalTime, 1000, TimeBase), MulDivU(ps->ps_TotalTime, 100000, TimeBase) % 100,
  302.     MulDivU(ps->ps_TotalTime, 100, total), MulDivU(ps->ps_TotalTime, 10000, total) % 100,
  303.     MulDivU(ps->ps_TimeStamp, 1000, TimeBase), MulDivU(ps->ps_TimeStamp, 100000, TimeBase) % 100,
  304.     MulDivU(ps->ps_TimeStamp, 100, total), MulDivU(ps->ps_TimeStamp, 10000, total) % 100
  305.     );
  306.  
  307.     if (limit) {
  308.     for (ps1 = ProfList; ps1; ps1 = ps1->ps_Link) {
  309.         for (ps2 = ps1; ps2; ps2 = ps2->ps_SibLink) {
  310.         if (ps2->ps_Parent == ps) {
  311.             if (cnt == 0)
  312.             puts(" {");
  313.             DumpProfTree(total, ps2, tab + 4, limit - 1);
  314.             ++cnt;
  315.         }
  316.         }
  317.     }
  318.     }
  319.     if (cnt)
  320.     printf("%*.*s}\n", tab, tab, "");
  321.     else
  322.     puts("");
  323. }
  324.  
  325. void
  326. DumpCombineProfTree(ps)
  327. ProfSym *ps;
  328. {
  329.     ProfSym *ps2;
  330.     ProfSym *ps3;
  331.     long total = 0;
  332.     long local = 0;
  333.     long calls = 0;
  334.  
  335.     for (ps2 = ps; ps2; ps2 = ps2->ps_SibLink) {
  336.     if (NoLoop(ps, ps2))
  337.         total += ps2->ps_TotalTime;
  338.     calls += ps2->ps_NumCalls;
  339.     local += ps2->ps_TimeStamp;
  340.     }
  341.     if (calls == 0)
  342.     return;
  343.  
  344.     printf("%-*s calls=%-5ld tot=%5ld.%02d (%3d.%02d)  loc=%5ld.%02d (%3d.%02d)\n",
  345.     MaxSymLen, NameOf(ps),
  346.     calls,
  347.     MulDivU(total, 1000, TimeBase), MulDivU(total, 100000, TimeBase) % 100,
  348.     MulDivU(total, 100, total), MulDivU(total, 10000, total) % 100,
  349.     MulDivU(local, 1000, TimeBase), MulDivU(local, 100000, TimeBase) % 100,
  350.     MulDivU(local, 100, total), MulDivU(local, 10000, total) % 100
  351.     );
  352.  
  353.     /*
  354.      *    find all routines this routine explicitly calls
  355.      */
  356.  
  357.     for (ps2 = ProfList; ps2; ps2 = ps2->ps_Link) {
  358.     long subTotal = 0;
  359.     long subLocal = 0;
  360.     long subCalls = 0;
  361.  
  362.     /*
  363.      *  add totals for routines that we (ps) call.    For each ps2 element
  364.      *  check to see if it is called by ps.
  365.      */
  366.  
  367.     for (ps3 = ps2; ps3; ps3 = ps3->ps_SibLink) {
  368.         if (ps3->ps_Parent && ps3->ps_Parent->ps_Id == ps->ps_Id) {
  369.         subTotal += ps3->ps_TotalTime;
  370.         subCalls += ps3->ps_NumCalls;
  371.         subLocal += ps3->ps_TimeStamp;
  372.  
  373.         /*
  374.          *  Scan the baselist backwards looking for this ps3.
  375.          *  If found then subtract the base total entry from
  376.          *  the subTotal since (1) the base is already counted
  377.          *  and (2) its subroutines have been or will be counted
  378.          *
  379.          *                B
  380.          *                 \
  381.          *                  Y     Y's total
  382.          *                   \
  383.          *                B   should not include B
  384.          */
  385.  
  386.         {
  387.             ProfSym *ps4;
  388.             ProfSym *ps5;
  389.  
  390.             for (ps4 = ps; ps4; ps4 = ps4->ps_SibLink) {
  391.             for (ps5 = ps4->ps_Parent; ps5; ps5 = ps5->ps_Parent) {
  392.                 if (ps5->ps_Id == ps->ps_Id)
  393.                 break;
  394.                 if (ps5 == ps3) {
  395.                 subTotal -= ps4->ps_TotalTime;
  396.                 break;
  397.                 }
  398.             }
  399.             }
  400.         }
  401.         }
  402.     }
  403.  
  404.     if (subCalls) {
  405.         if (ps2->ps_Id == ps->ps_Id) {
  406.         printf("    %-*s calls=%-5ld\n",
  407.             MaxSymLen, "<SELF>",
  408.             subCalls
  409.         );
  410.         } else {
  411.         printf("    %-*s calls=%-5ld tot=%5ld.%02d (%3d.%02d)  loc=%5ld.%02d (%3d.%02d)\n",
  412.             MaxSymLen, NameOf(ps2),
  413.             subCalls,
  414.             MulDivU(subTotal, 1000, TimeBase), MulDivU(subTotal, 100000, TimeBase) % 100,
  415.             MulDivU(subTotal, 100, total), MulDivU(subTotal, 10000, total) % 100,
  416.             MulDivU(subLocal, 1000, TimeBase), MulDivU(subLocal, 100000, TimeBase) % 100,
  417.             MulDivU(subLocal, 100, total), MulDivU(subLocal, 10000, total) % 100
  418.         );
  419.         }
  420.     }
  421.     }
  422. }
  423.  
  424.  
  425. char *
  426. NameOf(psc)
  427. ProfSym *psc;
  428. {
  429.     if (psc == NULL)
  430.     return("<root>");
  431.     return(ProfAry[psc->ps_Id]->ps_FuncName);
  432. }
  433.  
  434. void
  435. SortProfList()
  436. {
  437.     ProfSym *ps;
  438.     ProfSym *psnext;
  439.     ProfSym **pp;
  440.     long total = 0;
  441.  
  442.     for (ps = ProfList, ProfList = NULL; ps; ps = psnext) {
  443.     psnext = ps->ps_Link;
  444.  
  445.     for (pp = &ProfList; *pp; pp = &(*pp)->ps_Link) {
  446.         if (ps->ps_AccumTime > (*pp)->ps_AccumTime)
  447.         break;
  448.     }
  449.     ps->ps_Link = *pp;
  450.     *pp = ps;
  451.     }
  452. }
  453.  
  454. /*
  455.  *  Ensure that no parent of node is in the baselist
  456.  */
  457.  
  458. short
  459. NoLoop(base, node)
  460. ProfSym *base;
  461. ProfSym *node;
  462. {
  463.     if (node) {
  464.     while (node = node->ps_Parent) {
  465.         if (node->ps_Id == base->ps_Id)
  466.         return(0);
  467.     }
  468.     }
  469.     return(1);
  470. }
  471.  
  472.